﻿using System;
using System.Collections.Generic;
using System.Text;

namespace Imgalib.Utility
{
    public enum CreditCardType
    {
        Visa = 0,
        MasterCard,
        AmericanExpress,
        Discover,
        Unrecognized
    }

    public class CreditCardUtility
    {
        /// <summary>
        /// Validate Credit card Number format against Credit card type.
        /// Eanch type of credit card has its own format.
        /// </summary>
        /// <param name="type">Credit Card Type like Visa,Discover etc.</param>
        /// <param name="catdNo">creditcard no to validate</param>
        /// <returns></returns>
        public static bool IsVaildCardNo(CreditCardType type, string cardNo)
        {
            bool isValid = false;

            switch (type)
            {
                case CreditCardType.AmericanExpress: isValid = (CheckLength(cardNo, 15) && (CheckPrefix(cardNo, "34") || CheckPrefix(cardNo, "37"))); break;
                case CreditCardType.Discover: isValid = (CheckLength(cardNo, 16) && CheckPrefix(cardNo, "6011")); break;
                case CreditCardType.MasterCard: isValid = (CheckLength(cardNo, 16) && CheckPrefix(cardNo, "5")); break;
                case CreditCardType.Visa: isValid = ((CheckLength(cardNo, 13) || CheckLength(cardNo, 16)) && CheckPrefix(cardNo, "4")); break;
                case CreditCardType.Unrecognized: isValid = false; break;
            }
            return isValid;
        }

        private static bool CheckLength(string cardNo, int length)
        {
            return (cardNo.Length == length);
        }

        private static bool CheckPrefix(string cardNo, string prefix)
        {
            return cardNo.StartsWith(prefix);
        }

        /// <summary>
        /// Identify CreditCared type using Luhn algorithm
        /// </summary>
        /// <param name="CardNumber">creditcard no to validate</param>
        /// <returns></returns>
        public static CreditCardType CheckCreditCard(string cardNo)
        {
           bool isValid = false;
           CreditCardType result = CreditCardType.Unrecognized;
            byte[] number = new byte[16]; // number to validate

            // Remove non-digits
            int len = 0;
            for (int i = 0; i < cardNo.Length; i++)
            {
                if (char.IsDigit(cardNo, i))
                {
                    if (len == 16) return result=CreditCardType.Unrecognized; // number has too many digits
                    number[len++] = byte.Parse(cardNo[i].ToString());
                }
            }

            // Use Luhn Algorithm to validate
            int sum = 0;
            for (int i = len - 1; i >= 0; i--)
            {
                if (i % 2 == len % 2)
                {
                    int n = number[i] * 2;
                    sum += (n / 10) + (n % 10);
                }
                else
                    sum += number[i];
            }

            isValid = (bool)(sum % 10 == 0);

            if ((isValid))
            {
                switch (cardNo.Substring(0, 1))
                {
                    case "4":
                        result = CreditCardType.Visa;
                        break;
                    case "5":
                        result = CreditCardType.MasterCard;
                        break;
                    case "6":
                        result = CreditCardType.Discover;
                        break;
                    default:
                        result = CreditCardType.Unrecognized;
                        break;
                }
            }
            else
            {
                result=CreditCardType.Unrecognized;
            }
            return result;
        }
    }
}
